package com.p6spy.engine.event;

import com.p6spy.engine.common.CallableStatementInformation;
import com.p6spy.engine.common.ConnectionInformation;
import com.p6spy.engine.common.PreparedStatementInformation;
import com.p6spy.engine.common.ResultSetInformation;
import com.p6spy.engine.common.StatementInformation;

import java.sql.SQLException;
import java.util.ArrayList;
import java.util.Collections;
import java.util.List;

public class CompoundJdbcEventListener extends JdbcEventListener {
    private final List<JdbcEventListener> eventListeners;

    public CompoundJdbcEventListener() {
        eventListeners = new ArrayList<JdbcEventListener>();
    }

    public CompoundJdbcEventListener(List<JdbcEventListener> eventListeners) {
        this.eventListeners = eventListeners;
    }


    /**
     * Adds a listener to this {@link CompoundJdbcEventListener}
     *
     * @param listener The listener to add
     * @deprecated This method name has a typo, please use {@link CompoundJdbcEventListener#addListener}
     */
    public void addListender(JdbcEventListener listener) {
        addListener(listener);
    }

    /**
     * Adds a listener to this {@link CompoundJdbcEventListener}
     *
     * @param listener The listener to add
     */
    public void addListener(JdbcEventListener listener) {
        eventListeners.add(listener);
    }

    /**
     * Returns a read only view of the registered {@link JdbcEventListener}s
     *
     * @return a read only view of the registered {@link JdbcEventListener}s
     */
    public List<JdbcEventListener> getEventListeners() {
        return Collections.unmodifiableList(eventListeners);
    }

    @Override
    public void onBeforeGetConnection(ConnectionInformation connectionInformation) {
        for (JdbcEventListener eventListener : eventListeners) {
            eventListener.onBeforeGetConnection(connectionInformation);
        }
    }

    @Override
    public void onAfterGetConnection(ConnectionInformation connectionInformation, SQLException e) {
        for (JdbcEventListener eventListener : eventListeners) {
            eventListener.onAfterGetConnection(connectionInformation, e);
        }
    }

    @Override
    @Deprecated
    public void onConnectionWrapped(ConnectionInformation connectionInformation) {
        for (JdbcEventListener eventListener : eventListeners) {
            eventListener.onConnectionWrapped(connectionInformation);
        }
    }

    @Override
    public void onBeforeAddBatch(PreparedStatementInformation statementInformation) {
        for (JdbcEventListener eventListener : eventListeners) {
            eventListener.onBeforeAddBatch(statementInformation);
        }
    }

    @Override
    public void onAfterAddBatch(PreparedStatementInformation statementInformation, long timeElapsedNanos, SQLException e) {
        for (JdbcEventListener eventListener : eventListeners) {
            eventListener.onAfterAddBatch(statementInformation, timeElapsedNanos, e);
        }
    }

    @Override
    public void onBeforeAddBatch(StatementInformation statementInformation, String sql) {
        for (JdbcEventListener eventListener : eventListeners) {
            eventListener.onBeforeAddBatch(statementInformation, sql);
        }
    }

    @Override
    public void onAfterAddBatch(StatementInformation statementInformation, long timeElapsedNanos, String sql, SQLException e) {
        for (JdbcEventListener eventListener : eventListeners) {
            eventListener.onAfterAddBatch(statementInformation, timeElapsedNanos, sql, e);
        }
    }

    @Override
    public void onBeforeExecute(PreparedStatementInformation statementInformation) {
        for (JdbcEventListener eventListener : eventListeners) {
            eventListener.onBeforeExecute(statementInformation);
        }
    }

    @Override
    public void onAfterExecute(PreparedStatementInformation statementInformation, long timeElapsedNanos, SQLException e) {
        for (JdbcEventListener eventListener : eventListeners) {
            eventListener.onAfterExecute(statementInformation, timeElapsedNanos, e);
        }
    }

    @Override
    public void onBeforeExecute(StatementInformation statementInformation, String sql) {
        for (JdbcEventListener eventListener : eventListeners) {
            eventListener.onBeforeExecute(statementInformation, sql);
        }
    }

    /**
     * 在SQL语句执行完毕后触发的回调方法，实现了观察者模式中的通知逻辑。
     *
     * <p>在该方法中，遍历了所有注册到事件监听器列表（`eventListeners`）中的 {@link JdbcEventListener}，
     * 并依次调用它们的 `onAfterExecute` 方法。这样，每当有SQL语句执行完成时，
     * 所有的监听器都能接收到相关通知，并基于提供的参数（如：执行耗时、SQL语句信息以及可能抛出的异常）进行相应的处理或记录。

     * @param statementInformation 包含SQL语句执行上下文的封装对象
     * @param timeElapsedNanos SQL语句执行所花费的时间，单位为纳秒
     * @param sql 实际执行的SQL语句内容
     * @param e 可能抛出的{@link SQLException}，如果没有异常，则为null
     */
    @Override
    public void onAfterExecute(StatementInformation statementInformation, long timeElapsedNanos, String sql, SQLException e) {
        // 遍历并通知所有的JDBC事件监听器
        for (JdbcEventListener eventListener : eventListeners) {
            // 调用监听器的方法以响应SQL执行完成事件
            eventListener.onAfterExecute(statementInformation, timeElapsedNanos, sql, e);
        }
    }


    @Override
    public void onBeforeExecuteBatch(StatementInformation statementInformation) {
        for (JdbcEventListener eventListener : eventListeners) {
            eventListener.onBeforeExecuteBatch(statementInformation);
        }
    }

    @Override
    public void onAfterExecuteBatch(StatementInformation statementInformation, long timeElapsedNanos, int[] updateCounts, SQLException e) {
        for (JdbcEventListener eventListener : eventListeners) {
            eventListener.onAfterExecuteBatch(statementInformation, timeElapsedNanos, updateCounts, e);
        }
    }

    @Override
    public void onBeforeExecuteUpdate(PreparedStatementInformation statementInformation) {
        for (JdbcEventListener eventListener : eventListeners) {
            eventListener.onBeforeExecuteUpdate(statementInformation);
        }
    }

    @Override
    public void onAfterExecuteUpdate(PreparedStatementInformation statementInformation, long timeElapsedNanos, int rowCount, SQLException e) {
        for (JdbcEventListener eventListener : eventListeners) {
            eventListener.onAfterExecuteUpdate(statementInformation, timeElapsedNanos, rowCount, e);
        }
    }

    @Override
    public void onBeforeExecuteUpdate(StatementInformation statementInformation, String sql) {
        for (JdbcEventListener eventListener : eventListeners) {
            eventListener.onBeforeExecuteUpdate(statementInformation, sql);
        }
    }

    @Override
    public void onAfterExecuteUpdate(StatementInformation statementInformation, long timeElapsedNanos, String sql, int rowCount, SQLException e) {
        for (JdbcEventListener eventListener : eventListeners) {
            eventListener.onAfterExecuteUpdate(statementInformation, timeElapsedNanos, sql, rowCount, e);
        }
    }

    @Override
    public void onBeforeExecuteQuery(PreparedStatementInformation statementInformation) {
        for (JdbcEventListener eventListener : eventListeners) {
            eventListener.onBeforeExecuteQuery(statementInformation);
        }
    }

    @Override
    public void onAfterExecuteQuery(PreparedStatementInformation statementInformation, long timeElapsedNanos, SQLException e) {
        for (JdbcEventListener eventListener : eventListeners) {
            eventListener.onAfterExecuteQuery(statementInformation, timeElapsedNanos, e);
        }
    }

    @Override
    public void onBeforeExecuteQuery(StatementInformation statementInformation, String sql) {
        for (JdbcEventListener eventListener : eventListeners) {
            eventListener.onBeforeExecuteQuery(statementInformation, sql);
        }
    }

    /**
     * 在执行SQL查询后调用此方法，用于通知所有已注册的JdbcEventListener。
     *
     * @param statementInformation 包含关于当前执行SQL语句的Statement信息的对象
     * @param timeElapsedNanos     执行该SQL查询所花费的时间，单位为纳秒
     * @param sql                  完整的被执行的SQL语句
     * @param e                    如果在执行查询过程中发生了异常，则传递该SQLException对象；如果没有异常，则为null
     */
    @Override
    public void onAfterExecuteQuery(StatementInformation statementInformation, long timeElapsedNanos, String sql, SQLException e) {
        // 遍历并调用所有注册到p6spy的JdbcEventListener的onAfterExecuteQuery方法
        for (JdbcEventListener eventListener : eventListeners) {
            eventListener.onAfterExecuteQuery(statementInformation, timeElapsedNanos, sql, e);
        }
    }


    @Override
    public void onAfterPreparedStatementSet(PreparedStatementInformation statementInformation, int parameterIndex, Object value, SQLException e) {
        for (JdbcEventListener eventListener : eventListeners) {
            eventListener.onAfterPreparedStatementSet(statementInformation, parameterIndex, value, e);
        }
    }

    @Override
    public void onAfterCallableStatementSet(CallableStatementInformation statementInformation, String parameterName, Object value, SQLException e) {
        for (JdbcEventListener eventListener : eventListeners) {
            eventListener.onAfterCallableStatementSet(statementInformation, parameterName, value, e);
        }
    }

    @Override
    public void onAfterGetResultSet(StatementInformation statementInformation, long timeElapsedNanos, SQLException e) {
        for (JdbcEventListener eventListener : eventListeners) {
            eventListener.onAfterGetResultSet(statementInformation, timeElapsedNanos, e);
        }
    }

    @Override
    public void onBeforeResultSetNext(ResultSetInformation resultSetInformation) {
        for (JdbcEventListener eventListener : eventListeners) {
            eventListener.onBeforeResultSetNext(resultSetInformation);
        }
    }

    @Override
    public void onAfterResultSetNext(ResultSetInformation resultSetInformation, long timeElapsedNanos, boolean hasNext, SQLException e) {
        for (JdbcEventListener eventListener : eventListeners) {
            eventListener.onAfterResultSetNext(resultSetInformation, timeElapsedNanos, hasNext, e);
        }
    }

    @Override
    public void onAfterResultSetClose(ResultSetInformation resultSetInformation, SQLException e) {
        for (JdbcEventListener eventListener : eventListeners) {
            eventListener.onAfterResultSetClose(resultSetInformation, e);
        }
    }

    @Override
    public void onAfterResultSetGet(ResultSetInformation resultSetInformation, String columnLabel, Object value, SQLException e) {
        for (JdbcEventListener eventListener : eventListeners) {
            eventListener.onAfterResultSetGet(resultSetInformation, columnLabel, value, e);
        }
    }

    @Override
    public void onAfterResultSetGet(ResultSetInformation resultSetInformation, int columnIndex, Object value, SQLException e) {
        for (JdbcEventListener eventListener : eventListeners) {
            eventListener.onAfterResultSetGet(resultSetInformation, columnIndex, value, e);
        }
    }

    @Override
    public void onBeforeCommit(ConnectionInformation connectionInformation) {
        for (JdbcEventListener eventListener : eventListeners) {
            eventListener.onBeforeCommit(connectionInformation);
        }
    }

    @Override
    public void onAfterCommit(ConnectionInformation connectionInformation, long timeElapsedNanos, SQLException e) {
        for (JdbcEventListener eventListener : eventListeners) {
            eventListener.onAfterCommit(connectionInformation, timeElapsedNanos, e);
        }
    }

    @Override
    public void onAfterConnectionClose(ConnectionInformation connectionInformation, SQLException e) {
        for (JdbcEventListener eventListener : eventListeners) {
            eventListener.onAfterConnectionClose(connectionInformation, e);
        }
    }

    @Override
    public void onBeforeRollback(ConnectionInformation connectionInformation) {
        for (JdbcEventListener eventListener : eventListeners) {
            eventListener.onBeforeRollback(connectionInformation);
        }
    }

    @Override
    public void onAfterRollback(ConnectionInformation connectionInformation, long timeElapsedNanos, SQLException e) {
        for (JdbcEventListener eventListener : eventListeners) {
            eventListener.onAfterRollback(connectionInformation, timeElapsedNanos, e);
        }
    }

    @Override
    public void onAfterStatementClose(StatementInformation statementInformation, SQLException e) {
        for (JdbcEventListener eventListener : eventListeners) {
            eventListener.onAfterStatementClose(statementInformation, e);
        }
    }

    @Override
    public void onBeforeSetAutoCommit(ConnectionInformation connectionInformation, boolean newAutoCommit, boolean currentAutoCommit) {
        for (JdbcEventListener eventListener : eventListeners) {
            eventListener.onBeforeSetAutoCommit(connectionInformation, newAutoCommit, currentAutoCommit);
        }
    }

    @Override
    public void onAfterSetAutoCommit(ConnectionInformation connectionInformation, boolean newAutoCommit, boolean oldAutoCommit, SQLException e) {
        for (JdbcEventListener eventListener : eventListeners) {
            eventListener.onAfterSetAutoCommit(connectionInformation, newAutoCommit, oldAutoCommit, e);
        }
    }

}
